//只需引入request-promise-native
const rp = require('request-promise-native')
// 引入config
const config = require('../config/index.js')
// 引入api模块
const api = require('../util/api')
// 引入menu菜单模块
const menu = require('./menu.js')
// 引入写 读 模块
const {writeFileAsync,readFileAsync} = require('../util/tool')


//定义类   获取access_token等
class Wechat {
    constructor() {


    }

    /**
     * 获取access_token的方法---------------------------------------------------------------------------------------------------------------------------------
     */
    getAccessToken() {

        //定义请求地址
        const url = `${api.accessToken}&appid=${config.appId}&secret=${config.appsecret} `

        // 发送请求
        /**
         * request
         * request-promise-native 返回值是一个promise对象
         */
        return new Promise((resolve, reject) => {
            rp({
                    method: 'GET',
                    url,
                    json: true
                })
                .then((res) => {
                    // console.log(res)
                    /**
                     * {access_token: '45_t7kD1kfV-Q6uxeXpgQg2o6Bf4tnEtJMB8HxADRq…1KAFWoleA0kGxCpHypo3PLqU5VGKrhiKJAdAHATSJ', expires_in: 7200}
                     */

                    // 设置access_token过期时间,在2小时到来的提前5分钟设置过期
                    console.log(Date.now(),res.expires_in)
                    res.expires_in = Date.now() + (res.expires_in - 300) * 1000
                    // 将promise对象状态改成成功状态 
                    resolve(res);
                })
                .catch((err) => {
                    console.log(err)
                    // 将promise对象状态改成失败状态 
                    reject('getAccessToken方法出错了' + err)
                })
        })
    }
    /**
     * 保存access_token的方法
     */
    saveAccessToken(accessToken) {
        return writeFileAsync(accessToken,'accessToken.txt')
    }

    /**
     * 读取access_token的方法
     */
    readAccessToken() {
        return readFileAsync('accessToken.txt')
    }
    /**
     *  判断access_token是否有效
     */
    isAccessToken(data) {
        return new Promise((resolve, reject) => {
            if (!data && !data.access_token && !data.expires_in) {
                //代表access_token无效
                // console.log(data.expires_in,Date.now())
                return false
            }
            // 检测access_token是否在有效期内
            // 1️⃣
            if(data.expires_in < Date.now()){
                // 过期了
                return false
            }else{
                // 在有效期内
                return true
            }
           
            //2️⃣
            // return data.expires_in < Date.now()?false:true
           
            // 3️⃣
            // return data.expires_in > Date.now()
        })
    }
    // 封装fetchAccessToken方法,用来获取们没有过期的access_token
    fetchAccessToken() {
        //优化
        if(this.access_token && this.expires_in && this.isAccessToken(this)){
            //说明之前保存过access_token,并且是有效的，直接使用
            // console.log('本地有，未过期直接使用')
            return Promise.resolve({
                access_token: this.access_token,
                expires_in: this.expires_in
            })
        }
        // 是fetchAccessToken函数的返回值
        return this.readAccessToken()
            //判断有无本地access_token文件
            //1.本地有
            .then(async res => {
                // console.log('本地有')
                // 在判断
                if (this.isAccessToken(res)) {
                    // 1.1.access_token有效没过期
                    return Promise.resolve(res)
                } else {
                    // 1.2.发送请求获取access_token
                    const res = await this.getAccessToken()
                    // 请求到并保存本地为本地access_token文件
                    await this.saveAccessToken(res)
                    return Promise.resolve(res)
                }
            })
            .catch(async err => {
                // 2.本地无
                // 发送请求获取access_token
                // console.log('本地无')
                // 2.1.发送请求获取access_token
                 const res = await this.getAccessToken()
                 //请求到并保存本地为本地access_token文件
                 await this.saveAccessToken(res)
                 return Promise.resolve(res)
            })
            .then(res=>{
            // 将access_token挂载到this上
            this.access_token = res.access_token
            this.expires_in = res.expires_in
            // 返回res包装了一层Promise对象（此对象为成功状态）
            // this.readAccessToken()最终返回值
            return Promise.resolve(res)
            })
    }


    /**
     * 同理获取jsapi_ticket的方法----------------------------------------------------------------------------------------------------------------------------
     */
    getTicket() {   
        return new Promise(async (resolve, reject) => {
            // 拿到access_token的值
            const data = await this.fetchAccessToken()
            // console.log('wocao ')
            // console.log(data.access_token)

            //定义请求地址
            const url = `${api.ticket}access_token=${data.access_token}&type=jsapi`
            console.log(url)

            rp({
                    method: 'GET',
                    url,
                    json: true
                })
                .then((res) => {
                    //拿到jsapi_ticket
                    
                    res.expires_in = Date.now() + (res.expires_in - 300) * 1000
                    console.log(res)
                    // const jsapiTicket = {ticket:res.ticket,expires_in:res.expires_in}
                    resolve({ticket:res.ticket,expires_in:res.expires_in});
                })
                .catch((err) => {
                    console.log(err)
                    reject('getTicket方法出错了' + err)
                })
        })
    }
    /**
     * 保存ticket的方法
     */
    saveTicket(ticket) {
        return writeFileAsync(ticket,'ticket.txt')
    }

    /**
     * 读取ticket的方法
     */
    readTicket() {
        return readFileAsync('ticket.txt')
    }
    /**
     *  判断ticket是否有效
     */
    isTicket(data) {
        return new Promise((resolve, reject) => {
            if (!data && !data.ticket && !data.expires_in) {
                //代表ticket无效
                // console.log(data.expires_in,Date.now())
                return false
            }
            // 检测ticket是否在有效期内
            if(data.expires_in < Date.now()){
                // 过期了
                return false
            }else{
                // 在有效期内
                // console.log(data)
                return true
            }
        })
    }
    // 封装fetchTicket方法,用来获取没有过期的ticket
    fetchTicket() {
        //优化
        if(this.ticket && this.ticket_expires_in && this.isTicket(this)){
            //说明之前保存过ticket,并且是有效的，直接使用
            console.log('直接使用')
            // console.log(this.ticket,this.ticket_expires_in)
            return Promise.resolve({
                ticket: this.ticket,
                expires_in: this.expires_in
            })
        }
        // 是fetchTicket函数的返回值
        return this.readTicket()
            //判断有无本地ticket文件
            //1.本地有
            .then(async res => {
                console.log('本地有')
                // 在判断
                if (this.isTicket(res)) {
                    // 1.1.ticket有效没过期
                    // console.log('没过期')
                    return Promise.resolve(res)
                } else {
                    // 过期了
                    // 1.2.发送请求获取ticket
                    const res = await this.getTicket()
                    // 请求到并保存本地为本地ticket文件
                    await this.saveTicket(res)
                    return Promise.resolve(res)
                }
            })
            .catch(async err => {
                // 2.本地无
                // 发送请求获取ticket
                // console.log('本地无')
                // 2.1.发送请求获取ticket
                 const res = await this.getTicket()
                 //请求到并保存本地为本地ticket文件
                 await this.saveTicket(res)
                 return Promise.resolve(res)
            })
            .then(res =>{
            // 将ticket挂载到this上
            this.ticket = res.ticket
            this.ticket_expires_in = res.expires_in
            // 返回res包装了一层Promise对象（此对象为成功状态）
            // this.readTicket()最终返回值
            return Promise.resolve(res) 
            })
    }



    // 创建自定义菜单
    createMenu(menu){
        return new Promise(async (resolve,reject)=>{
            try{
                //获取access_token
                const data = await this.fetchAccessToken()
                const url = `${api.menu.craete}access_token=${data.access_token}`
                //发送请求
                const result = await rp({method:'POST',url,json:true,body:menu})
                resolve(result)
            }
            catch(e){
                reject('createMenu方法出错了'+ e)
            }
        }) 
    }
    // 删除自定义菜单
    deleteMenu(){
        return new Promise(async (resolve,reject )=>{
            try{
                const data = await this.fetchAccessToken()
                const url = `${api.menu.delete}access_token=${data.access_token}`
                const result = await rp({method:'GET',url,json:true})
                resolve(result)
                console.log('删除成功')
            }catch(e){
                reject('deleteMenu方法出错了'+e)
            }
            
        })
    }
}

/*(async ()=>{
    // 模拟测试
    const w = new Wechat()
    // // 先删除之前定义的菜单
    // let result = await w.deleteMenu()
    // console.log(result)

    // // 再创建新的菜单
    // result = await w.createMenu(menu)
    // console.log(result)
    w.fetchTicket()
})()
*/


module.exports = Wechat

/**
 * 所有微信接口文件
 * 
 * accesss_token特点：
 *  1.唯一的凭证；
 *  2.有效时间为2小时，需提前5分钟请求；
 *  3.接口权限每天2000次。
 
    请求地址：
    https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
    (需要用到APPID，APPSECRET)
    请求方式：
    GET
    
    设计方式：

    查看本有无access_token文件（readAccessToken），
    1.有，
        判断是否过期(isAccessToken)： 
            过期了：重新通过url, get请求 (getAccessToken),保存并覆盖本地access_token文件(saveAccessToken) 
            没有过期：请求本地文件
    2.没有，
        直接通过url进行请求(getAccessToken)，并保存access_token(本地文件)(saveAccessToken)。       
*/



